<?php declare(strict_types=1);

namespace think\msg;

use SplObserver;
use SplSubject;
use think\App;
use think\facade\Queue;
use think\msg\job\MsgPushJob;
use think\msg\msg\Msg;
use think\msg\platform\MsgPlatform;
use think\msg\platform\MsgPlatformFactory;

class MsgContext implements SplSubject
{
    /**
     * @var Msg 消息模板
     */
    protected $msg;

    /**
     * @var MsgPlatform
     */
    protected $observers;

    /**
     * @var App
     */
    private $app;

    private $requestParams = [
        'url' => null,
        // 字符串格式
        'params' => null,
    ];

    /**
     * @var null|string 响应参数
     */
    private $responseBody = null;

    /**
     * @throws MsgException
     */
    public function __construct(App $app)
    {
        $this->app = $app;
        $platforms = $app->config->get('msg.platform');
        // 遍历配置的平台，添加到观察者列表中
        foreach ($platforms as $platform) {
            if (false === $platform['enable']) {
                continue;
            }
            $this->attach(MsgPlatformFactory::create($this, $platform));
        }
    }

    //<editor-fold desc="推送消息">

    /**
     * 异步推送消息
     * @return void
     */
    public function asyncSend(Msg $msg)
    {
        $requestId = $this->app->request->requestId;
        Queue::push(MsgPushJob::class, [
            'requestId' => $requestId,
            'msg' => $msg
        ], MsgPushJob::QUEUE_NAME);
    }

    public function send(Msg $msg)
    {
        $this->setMsg($msg);
        $this->notify();
    }
    //</editor-fold>

    //<editor-fold desc="观察者方法">
    public function attach(SplObserver $observer)
    {
        $this->observers[get_class($observer)] = $observer;
    }

    public function detach(SplObserver $observer)
    {
        unset($this->observers[get_class($observer)]);
    }

    public function notify()
    {
        foreach ($this->observers as $observer) {
            $observer->update($this);
        }
    }
    //</editor-fold>

    //<editor-fold desc="setterGetter方法">
    public function setMsg(Msg $msg): void
    {
        $this->msg = $msg;
    }

    public function getMsg(): Msg
    {
        return $this->msg;
    }

    public function setRequestParams(string $url, array $params = null): void
    {
        $this->requestParams = [
            'url' => $url,
            'params' => $params,
        ];
    }

    public function setResponseBody(?string $responseBody): void
    {
        $this->responseBody = $responseBody;
    }

    public function getLog(string $businessName): string
    {
        return sprintf('[%s] 请求地址：%s 请求参数：%s 响应结果：%s', $businessName, $this->requestParams['url'], json_encode($this->requestParams['params'], JSON_UNESCAPED_UNICODE), $this->responseBody);
    }
    //</editor-fold>
}
